package game.engine;

import java.util.*;

import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Vector2f;
import org.newdawn.slick.tiled.TiledMap;

public class World {

	private final int BACKGROUND_LAYER = 0;
	private final int MIDGROUND_LAYER = 1;
	private final int FOREGROUND_LAYER = 2;
	private final int COLLISION_LAYER = 3;
	private final int ITEM_LAYER = 4;
	private final int ENEMY_LAYER = 5;

	private String mapPath;
	private TiledMap myMap;
	private boolean[][] blockingArray;
	private List<Entity> allEntities;

	private int pixelWidth, pixelHeight;

	public World(String mapPath) {
		this.mapPath = mapPath;
	}

	public World() {
		// TODO test world
		try {
			myMap = new TiledMap("data/maps/untitled.tmx");
		} catch (SlickException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void init() {
		blockingArray = new boolean[myMap.getWidth()][myMap.getHeight()];
		allEntities = new ArrayList<Entity>();
		for (int xAxis = 0; xAxis < myMap.getWidth(); xAxis++) {
			for (int yAxis = 0; yAxis < myMap.getHeight(); yAxis++) {
				int collisionTile = myMap.getTileId(xAxis, yAxis, 0);
				String blocked = myMap.getTileProperty(collisionTile, "blocked", "false");
				// Translate them to game data
				blockingArray[xAxis][yAxis] = Boolean.parseBoolean(blocked);
			}
		}
	}

	public void render() {
		myMap.render(0, 0);
		for (Entity e : allEntities) {
			e.draw((int) e.getX() * GameConstants.TILE_SIZE, (int) e.getY() * GameConstants.TILE_SIZE);
		}
	}

	public List<Entity> getEntities() {
		return allEntities;
	}

	public void updateAllEntities(int delta) {
		for (Entity e : allEntities) {
			e.update();
			e.attemptMove();
		}
	}

	public void addEntity(Entity e) {
		e.setWorld(this);
		allEntities.add(e);
	}

	public void removeEntity(Entity e) {

	}

	// CONSIDER: The array we return only works as intended for when the players speed is < 1 TILE per frame. If he's moving faster than that, his next frame
	// might be outside of the array returned by this, and therefore, it will allow the movement to occur
	public boolean[][] getCollisionArray(Entity e) {
		float x = e.getX();
		float y = e.getY();
		float width = e.getSpriteWidth() + 1;
		float height = e.getSpriteHeight() + 1;
		int xCoord = (int) Math.floor(x / GameConstants.TILE_SIZE) - 1;
		int yCoord = (int) Math.floor(y / GameConstants.TILE_SIZE) - 1;
		// the '+ 2' below is to allow for the collision array to contain sufficient information about the blocks around the entity:
		// We need an additional 2 to account for:
		// - The tiles above/left of where the entity's top-left corner is. (needed when entity has negative velocity)
		// - The tiles the entity's bottom edge, right, edge, and bottom-right corner is in.
		// - The tiles below/right of where the entity's bottom-right corer is. (needed when entity has positive velocity)
		boolean[][] collisionArray = new boolean[(int) Math.ceil(width / 32) + 2][(int) Math.ceil(height / 32) + 2];
		for (int i = xCoord; i < xCoord + collisionArray.length; i++) {
			for (int j = yCoord; j < yCoord + collisionArray[0].length; j++) {
				if ((i >= 0 && i < blockingArray.length) && (j >= 0 && j < blockingArray[0].length)) {
					collisionArray[i - xCoord][j - yCoord] = blockingArray[i][j];
				}
				else {
					collisionArray[i - xCoord][j - yCoord] = true;
				}
			}
		}
		return collisionArray;
	}

	public int getPixelWidth() {
		return pixelWidth;
	}

	public int getPixelHeight() {
		return pixelHeight;
	}

	public boolean isSpaceOpen(Vector2f moveVector, float x, float y) {
		if (blockingArray[(int) (moveVector.getX() + x)][(int) (moveVector.getY() + y)])
			return false;
		else
			return true;
	}
}
